home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / tiff / tools / tiff2ps.c < prev    next >
C/C++ Source or Header  |  1992-03-30  |  14KB  |  548 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Header: /usr/people/sam/tiff/tools/RCS/tiff2ps.c,v 1.21 92/03/31 10:53:36 sam Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Copyright (c) 1988, 1989, 1990, 1991, 1992 Sam Leffler
  7.  * Copyright (c) 1991, 1992 Silicon Graphics, Inc.
  8.  *
  9.  * Permission to use, copy, modify, distribute, and sell this software and 
  10.  * its documentation for any purpose is hereby granted without fee, provided
  11.  * that (i) the above copyright notices and this permission notice appear in
  12.  * all copies of the software and related documentation, and (ii) the names of
  13.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  14.  * publicity relating to the software without the specific, prior written
  15.  * permission of Sam Leffler and Silicon Graphics.
  16.  * 
  17.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  18.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  19.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  20.  * 
  21.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  22.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  23.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  24.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  25.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  26.  * OF THIS SOFTWARE.
  27.  */
  28.  
  29. #include <math.h>
  30. #include <stdio.h>
  31. #include "tiffio.h"
  32.  
  33. typedef    unsigned char u_char;
  34. typedef    unsigned short u_short;
  35. typedef unsigned long u_long;
  36.  
  37. extern    double atof();
  38.  
  39. char    *filename;
  40.  
  41. main(argc, argv)
  42.     int argc;
  43.     char *argv[];
  44. {
  45.     int dirnum = -1, c;
  46.     TIFF *tif;
  47.     char *cp;
  48.     float width = 0.0;
  49.     float height = 0.0;
  50.     extern char *optarg;
  51.     extern int optind;
  52.  
  53.     while ((c = getopt(argc, argv, "h:H:w:W:d:")) != -1)
  54.         switch (c) {
  55.         case 'd':
  56.             dirnum = atoi(optarg);
  57.             break;
  58.         case 'h': case 'H':
  59.             height = atof(optarg);
  60.             break;
  61.         case 'w': case 'W':
  62.             width = atof(optarg);
  63.             break;
  64.         case '?':
  65.             usage(-1);
  66.         }
  67.     if (argc - optind < 1)
  68.         usage(-2);
  69.     tif = TIFFOpen(filename = argv[optind], "r");
  70.     if (tif != NULL) {
  71.         if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum))
  72.             exit(-1);
  73.         TIFF2PS(stdout, tif, width, height);
  74.     }
  75.     exit(0);
  76. }
  77.  
  78. usage(code)
  79.     int code;
  80. {
  81.     fprintf(stderr, "Usage: tiff2ps %s %s %s file\n"
  82.         , "[-w inches]"
  83.         , "[-h inches]"
  84.         , "[-d dirnum]"
  85.     );
  86.     exit(code);
  87. }
  88.  
  89. static    u_short samplesperpixel;
  90. static    u_short bitspersample;
  91. static    u_short planarconfiguration;
  92. static    u_short photometric;
  93. static    u_short matte = 0;
  94.  
  95. static
  96. checkImage(tif)
  97.     TIFF *tif;
  98. {
  99.     switch (bitspersample) {
  100.     case 1: case 2:
  101.     case 4: case 8:
  102.         break;
  103.     default:
  104.         TIFFError(filename, "Can not handle %d-bit/sample image",
  105.             bitspersample);
  106.         return (0);
  107.     }
  108.     switch (photometric) {
  109.     case PHOTOMETRIC_RGB:
  110.         if (matte && bitspersample != 8) {
  111.             TIFFError(filename,
  112.                 "Can not handle %d-bit/sample RGB image with alpha",
  113.                 bitspersample);
  114.             return (0);
  115.         }
  116.         /* fall thru... */
  117.     case PHOTOMETRIC_SEPARATED:
  118.     case PHOTOMETRIC_PALETTE:
  119.     case PHOTOMETRIC_MINISBLACK:
  120.     case PHOTOMETRIC_MINISWHITE:
  121.         break;
  122.     default:
  123.         TIFFError(filename,
  124.             "Can not handle image with PhotometricInterpretation=%d",
  125.             photometric);
  126.         return (0);
  127.     }
  128.     if (planarconfiguration == PLANARCONFIG_SEPARATE && matte)
  129.         TIFFWarning(filename, "Ignoring alpha data");
  130.     return (1);
  131. }
  132.  
  133. #define PS_UNIT_SIZE    72.0
  134. #define    PSUNITS(npix,res)    ((npix) * (PS_UNIT_SIZE / (res)))
  135.  
  136. static    char RGBcolorimage[] = "\
  137. /bwproc {\n\
  138.     rgbproc\n\
  139.     dup length 3 idiv string 0 3 0\n\
  140.     5 -1 roll {\n\
  141.     add 2 1 roll 1 sub dup 0 eq {\n\
  142.         pop 3 idiv\n\
  143.         3 -1 roll\n\
  144.         dup 4 -1 roll\n\
  145.         dup 3 1 roll\n\
  146.         5 -1 roll put\n\
  147.         1 add 3 0\n\
  148.     } { 2 1 roll } ifelse\n\
  149.     } forall\n\
  150.     pop pop pop\n\
  151. } def\n\
  152. /colorimage where {pop} {\n\
  153.     /colorimage {pop pop /rgbproc exch def {bwproc} image} bind def\n\
  154. } ifelse\n\
  155. ";
  156.  
  157. /*
  158.  * Adobe Photoshop requires a comment line of the form:
  159.  *
  160.  * %ImageData: <cols> <rows> <depth>  <main channels> <pad channels>
  161.  *    <block size> <1 for binary|2 for hex> "data start"
  162.  *
  163.  * It is claimed to be part of some future revision of the EPS spec.
  164.  */
  165. static
  166. PhotoshopBanner(fd, w, h, bs, nc, startline)
  167.     FILE *fd;
  168.     u_long w, h;
  169.     int bs, nc;
  170.     char *startline;
  171. {
  172.     fprintf(fd, "%%ImageData: %ld %ld %d %d 0 %d 2 \"",
  173.         w, h, bitspersample, nc, bs);
  174.     fprintf(fd, startline, nc);
  175.     fprintf(fd, "\"\n");
  176. }
  177.  
  178. static    u_short tf_bytesperrow;
  179. static    u_short ps_bytesperrow;
  180. static    char *hex = "0123456789abcdef";
  181.  
  182. TIFF2PS(fd, tif, width, height)
  183.     FILE* fd;
  184.     TIFF *tif;
  185.     float width, height;
  186. {
  187.     u_long w, h;
  188.     u_short res_tag, res_unit;
  189.     int bgc;
  190.     float ox, oy, xres, yres;
  191.     long t;
  192.     extern char *ctime();
  193.  
  194.     tf_bytesperrow = TIFFScanlineSize(tif);
  195.     TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  196.     TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
  197.     TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarconfiguration);
  198.     TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
  199.     TIFFGetField(tif, TIFFTAG_MATTEING, &matte);
  200.     if (!checkImage(tif))
  201.         return;
  202.  
  203.     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
  204.     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
  205.     if (!TIFFGetField(tif, TIFFTAG_XPOSITION, &ox))
  206.         ox = 0;
  207.     if (!TIFFGetField(tif, TIFFTAG_YPOSITION, &oy))
  208.         oy = 0;
  209.     if (!TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &res_unit))
  210.         res_tag = RESUNIT_NONE;
  211.     switch (res_tag) {
  212.     case RESUNIT_CENTIMETER:
  213.         res_unit = 2.54; /* centimeters per inch */
  214.         break;
  215.     case RESUNIT_INCH:
  216.     case RESUNIT_NONE:
  217.     default:
  218.         res_unit = 1.0;
  219.         break;
  220.     }
  221.     if (width == 0.0) {
  222.         if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres))
  223.             xres = PS_UNIT_SIZE / res_unit;
  224.     } else
  225.         xres = (float) w / width;
  226.     if (height == 0.0) {
  227.         if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres))
  228.             yres = PS_UNIT_SIZE / res_unit;
  229.     } else
  230.         yres = (float) h / height;
  231.  
  232.     t = time(0);
  233.     fprintf(fd, "%%!PS-Adobe-3.0 EPSF-3.0\n");
  234.     fprintf(fd, "%%%%Creator: tiff2ps\n");
  235.     fprintf(fd, "%%%%Title: %s\n", filename);
  236.     fprintf(fd, "%%%%CreationDate: %s", ctime(&t));
  237.     fprintf(fd, "%%%%Origin: %ld %ld\n", (long) ox, (long) oy);
  238.     fprintf(fd, "%%%%BoundingBox: 0 0 %ld %ld\n",
  239.         (long) ceil(PSUNITS(w,xres)), (long) ceil(PSUNITS(h,yres)));
  240.     fprintf(fd, "%%%%EndComments\n");
  241.     fprintf(fd, "gsave\n");
  242.     fprintf(fd, "10 dict begin\n");
  243.  
  244.     ps_bytesperrow = tf_bytesperrow;
  245.     switch (photometric) {
  246.     case PHOTOMETRIC_RGB:
  247.         if (planarconfiguration == PLANARCONFIG_CONTIG) {
  248.             fprintf(fd, "%s", RGBcolorimage);
  249.             PSColorContigPreamble(fd, w, h, xres, yres, 3);
  250.             PSDataColorContig(fd, tif, w, h, 3);
  251.         } else {
  252.             PSColorSeparatePreamble(fd, w, h, xres, yres, 3);
  253.             PSDataColorSeparate(fd, tif, w, h, 3);
  254.         }
  255.         break;
  256.     case PHOTOMETRIC_SEPARATED:
  257.         /* XXX should emit CMYKcolorimage */
  258.         if (planarconfiguration == PLANARCONFIG_CONTIG) {
  259.             PSColorContigPreamble(fd, w, h, xres, yres, 4);
  260.             PSDataColorContig(fd, tif, w, h, 4);
  261.         } else {
  262.             PSColorSeparatePreamble(fd, w, h, xres, yres, 4);
  263.             PSDataColorSeparate(fd, tif, w, h, 4);
  264.         }
  265.         break;
  266.     case PHOTOMETRIC_PALETTE:
  267.         fprintf(fd, "%s", RGBcolorimage);
  268.         PhotoshopBanner(fd, w, h, 1, 3, "false 3 colorimage");
  269.         fprintf(fd, "/scanLine %d string def\n", ps_bytesperrow);
  270.         fprintf(fd, "%f %f scale\n",
  271.             (float) PSUNITS(w,xres), (float) PSUNITS(h,yres));
  272.         fprintf(fd, "%lu %lu 8\n", w, h);
  273.         fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n", w, h, h);
  274.         fprintf(fd, "{currentfile scanLine readhexstring pop} bind\n");
  275.         fprintf(fd, "false 3 colorimage\n");
  276.         PSDataPalette(fd, tif, w, h);
  277.         break;
  278.     case PHOTOMETRIC_MINISBLACK:
  279.     case PHOTOMETRIC_MINISWHITE:
  280.         PhotoshopBanner(fd, w, h, 1, 1, "image");
  281.         fprintf(fd, "/scanLine %d string def\n", ps_bytesperrow);
  282.         fprintf(fd, "%f %f scale\n",
  283.             (float) PSUNITS(w,xres), (float) PSUNITS(h,yres));
  284.         fprintf(fd, "%lu %lu %d\n", w, h, bitspersample);
  285.         fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n", w, h, h);
  286.         fprintf(fd, "{currentfile scanLine readhexstring pop} bind\n");
  287.         fprintf(fd, "image\n");
  288.         PSDataBW(fd, tif, w, h);
  289.         break;
  290.     }
  291.     putc('\n', fd);
  292.     fprintf(fd, "end\n");
  293.     fprintf(fd, "grestore\n");
  294.     fprintf(fd, "showpage\n");
  295.     fprintf(fd, "%%%%Trailer\n");
  296. }
  297.  
  298. PSColorContigPreamble(fd, w, h, xres, yres, nc)
  299.     FILE *fd;
  300.     u_long w, h;
  301.     float xres, yres;
  302.     int nc;
  303. {
  304.     ps_bytesperrow = (u_short) nc * (tf_bytesperrow / samplesperpixel);
  305.     PhotoshopBanner(fd, w, h, 1, nc, "false %d colorimage");
  306.     fprintf(fd, "/line %d string def\n", ps_bytesperrow);
  307.     fprintf(fd, "%f %f scale\n",
  308.         (float) PSUNITS(w,xres), (float) PSUNITS(h,yres));
  309.     fprintf(fd, "%lu %lu %d\n", w, h, bitspersample);
  310.     fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n", w, h, h);
  311.     fprintf(fd, "{currentfile line readhexstring pop} bind\n");
  312.     fprintf(fd, "false %d colorimage\n", nc);
  313. }
  314.  
  315. PSColorSeparatePreamble(fd, w, h, xres, yres, nc)
  316.     FILE *fd;
  317.     u_long w, h;
  318.     float xres, yres;
  319.     int nc;
  320. {
  321.     int i;
  322.  
  323.     PhotoshopBanner(fd, w, h, ps_bytesperrow, nc, "true %d colorimage");
  324.     for (i = 0; i < nc; i++)
  325.         fprintf(fd, "/line%d %d string def\n", i, ps_bytesperrow);
  326.     fprintf(fd, "%f %f scale\n",
  327.         (float) PSUNITS(w,xres), (float) PSUNITS(h,yres));
  328.     fprintf(fd, "%lu %lu %d\n", w, h, bitspersample);
  329.     fprintf(fd, "[%lu 0 0 -%lu 0 %lu] \n", w, h, h);
  330.     for (i = 0; i < nc; i++)
  331.         fprintf(fd, "{currentfile line%d readhexstring pop}bind\n", i);
  332.     fprintf(fd, "true %d colorimage\n", nc);
  333. }
  334.  
  335. #define MAXLINE        36
  336. #define    DOBREAK(len, howmany, fd) \
  337.     if (((len) -= (howmany)) <= 0) {    \
  338.         putc('\n', fd);            \
  339.         (len) = MAXLINE-(howmany);    \
  340.     }
  341. #define    PUTHEX(c,fd)    putc(hex[((c)>>4)&0xf],fd); putc(hex[(c)&0xf],fd)
  342.  
  343. PSDataColorContig(fd, tif, w, h, nc)
  344.     FILE* fd;
  345.     TIFF* tif;
  346.     u_long w, h;
  347.     int nc;
  348. {
  349.     u_long row;
  350.     int breaklen = MAXLINE, cc, es = samplesperpixel - nc;
  351.     u_char *tf_buf;
  352.     u_char *cp, c;
  353.  
  354.     tf_buf = (u_char *) malloc(tf_bytesperrow);
  355.     if (tf_buf == NULL) {
  356.         TIFFError(filename, "No space for scanline buffer");
  357.         return;
  358.     }
  359.     for (row = 0; row < h; row++) {
  360.         if (TIFFReadScanline(tif, tf_buf, row, 0) < 0)
  361.             break;
  362.         cp = tf_buf;
  363.         if (matte) {
  364.             int adjust;
  365.             cc = 0;
  366.             for (; cc < tf_bytesperrow; cc += samplesperpixel) {
  367.                 DOBREAK(breaklen, nc, fd);
  368.                 /*
  369.                  * For images with alpha, matte against
  370.                  * a white background; i.e.
  371.                  *    Cback * (1 - Aimage)
  372.                  * where Cback = 1.
  373.                  */
  374.                 adjust = 255 - cp[nc];
  375.                 switch (nc) {
  376.                 case 4: c = *cp++ + adjust; PUTHEX(c,fd);
  377.                 case 3: c = *cp++ + adjust; PUTHEX(c,fd);
  378.                 case 2: c = *cp++ + adjust; PUTHEX(c,fd);
  379.                 case 1: c = *cp++ + adjust; PUTHEX(c,fd);
  380.                 }
  381.                 cp += es;
  382.             }
  383.         } else {
  384.             cc = 0;
  385.             for (; cc < tf_bytesperrow; cc += samplesperpixel) {
  386.                 DOBREAK(breaklen, nc, fd);
  387.                 switch (nc) {
  388.                 case 4: c = *cp++; PUTHEX(c,fd);
  389.                 case 3: c = *cp++; PUTHEX(c,fd);
  390.                 case 2: c = *cp++; PUTHEX(c,fd);
  391.                 case 1: c = *cp++; PUTHEX(c,fd);
  392.                 }
  393.                 cp += es;
  394.             }
  395.         }
  396.     }
  397.     free((char *) tf_buf);
  398. }
  399.  
  400. PSDataColorSeparate(fd, tif, w, h, nc)
  401.     FILE* fd;
  402.     TIFF* tif;
  403.     u_long w, h;
  404.     int nc;
  405. {
  406.     u_long row;
  407.     int breaklen = MAXLINE, cc, s, maxs;
  408.     u_char *tf_buf;
  409.     u_char *cp, c;
  410.  
  411.     tf_buf = (u_char *) malloc(tf_bytesperrow);
  412.     if (tf_buf == NULL) {
  413.         TIFFError(filename, "No space for scanline buffer");
  414.         return;
  415.     }
  416.     maxs = (samplesperpixel > nc ? nc : samplesperpixel);
  417.     for (row = 0; row < h; row++) {
  418.         for (s = 0; s < maxs; s++) {
  419.             if (TIFFReadScanline(tif, tf_buf, row, s) < 0)
  420.                 break;
  421.             for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) {
  422.                 DOBREAK(breaklen, 1, fd);
  423.                 c = *cp++;
  424.                 PUTHEX(c,fd);
  425.             }
  426.         }
  427.     }
  428.     free((char *) tf_buf);
  429. }
  430.  
  431. #define    PUTRGBHEX(c,fd) \
  432.     PUTHEX(rmap[c],fd); PUTHEX(gmap[c],fd); PUTHEX(bmap[c],fd)
  433.  
  434. static int
  435. checkcmap(tif, n, r, g, b)
  436.     TIFF *tif;
  437.     int n;
  438.     u_short *r, *g, *b;
  439. {
  440.     while (n-- > 0)
  441.         if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
  442.             return (16);
  443.     TIFFWarning(filename, "Assuming 8-bit colormap");
  444.     return (8);
  445. }
  446.  
  447. PSDataPalette(fd, tif, w, h)
  448.     FILE* fd;
  449.     TIFF* tif;
  450.     u_long w, h;
  451. {
  452.     u_short *rmap, *gmap, *bmap;
  453.     u_long row;
  454.     int breaklen = MAXLINE, cc, nc;
  455.     u_char *tf_buf;
  456.     u_char *cp, c;
  457.  
  458.     if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
  459.         TIFFError(filename, "Palette image w/o \"Colormap\" tag");
  460.         return;
  461.     }
  462.     switch (bitspersample) {
  463.     case 8:    case 4: case 2: case 1:
  464.         break;
  465.     default:
  466.         TIFFError(filename, "Depth %d not supported", bitspersample);
  467.         return;
  468.     }
  469.     nc = 3 * (8 / bitspersample);
  470.     tf_buf = (u_char *) malloc(tf_bytesperrow);
  471.     if (tf_buf == NULL) {
  472.         TIFFError(filename, "No space for scanline buffer");
  473.         return;
  474.     }
  475.     if (checkcmap(tif, 1<<bitspersample, rmap, gmap, bmap) == 16) {
  476.         int i;
  477. #define    CVT(x)        (((x) * 255) / ((1L<<16)-1))
  478.         for (i = (1<<bitspersample)-1; i > 0; i--) {
  479.             rmap[i] = CVT(rmap[i]);
  480.             gmap[i] = CVT(gmap[i]);
  481.             bmap[i] = CVT(bmap[i]);
  482.         }
  483. #undef CVT
  484.     }
  485.     for (row = 0; row < h; row++) {
  486.         if (TIFFReadScanline(tif, tf_buf, row, 0) < 0)
  487.             break;
  488.         for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) {
  489.             DOBREAK(breaklen, nc, fd);
  490.             switch (bitspersample) {
  491.             case 8:
  492.                 c = *cp++; PUTRGBHEX(c, fd);
  493.                 break;
  494.             case 4:
  495.                 c = *cp++; PUTRGBHEX(c&0xf, fd);
  496.                 c >>= 4;   PUTRGBHEX(c, fd);
  497.                 break;
  498.             case 2:
  499.                 c = *cp++; PUTRGBHEX(c&0x3, fd);
  500.                 c >>= 2;   PUTRGBHEX(c&0x3, fd);
  501.                 c >>= 2;   PUTRGBHEX(c&0x3, fd);
  502.                 c >>= 2;   PUTRGBHEX(c, fd);
  503.                 break;
  504.             case 1:
  505.                 c = *cp++; PUTRGBHEX(c&0x1, fd);
  506.                 c >>= 1;   PUTRGBHEX(c&0x1, fd);
  507.                 c >>= 1;   PUTRGBHEX(c&0x1, fd);
  508.                 c >>= 1;   PUTRGBHEX(c&0x1, fd);
  509.                 c >>= 1;   PUTRGBHEX(c&0x1, fd);
  510.                 c >>= 1;   PUTRGBHEX(c&0x1, fd);
  511.                 c >>= 1;   PUTRGBHEX(c&0x1, fd);
  512.                 c >>= 1;   PUTRGBHEX(c, fd);
  513.                 break;
  514.             }
  515.         }
  516.     }
  517.     free((char *) tf_buf);
  518. }
  519.  
  520. PSDataBW(fd, tif, w, h)
  521.     FILE* fd;
  522.     TIFF* tif;
  523.     u_long w, h;
  524. {
  525.     u_long row;
  526.     int breaklen = MAXLINE, cc;
  527.     u_char *tf_buf;
  528.     u_char *cp, c;
  529.  
  530.     tf_buf = (u_char *) malloc(tf_bytesperrow);
  531.     if (tf_buf == NULL) {
  532.         TIFFError(filename, "No space for scanline buffer");
  533.         return;
  534.     }
  535.     for (row = 0; row < h; row++) {
  536.         if (TIFFReadScanline(tif, tf_buf, row, 0) < 0)
  537.             break;
  538.         for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) {
  539.             DOBREAK(breaklen, 1, fd);
  540.             c = *cp++;
  541.             if (photometric == PHOTOMETRIC_MINISWHITE)
  542.                 c = ~c;
  543.             PUTHEX(c, fd);
  544.         }
  545.     }
  546.     free((char *) tf_buf);
  547. }
  548.